#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
智能出行路径规划系统
支持多式联运、智能中转、全局优化的高级功能
"""

import json
import requests
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from enum import Enum
import heapq
import math

class TransportMode(Enum):
    """交通方式枚举"""
    FLIGHT = "flight"
    HIGH_SPEED_RAIL = "high_speed_rail"
    TRAIN = "train"
    BUS = "bus"
    METRO = "metro"

class OptimizationType(Enum):
    """优化类型枚举"""
    TIME = "time"           # 时间最短
    COST = "cost"           # 费用最低
    COMFORT = "comfort"     # 舒适度最高
    BALANCED = "balanced"   # 平衡优化

@dataclass
class TransportLeg:
    """交通段信息"""
    mode: TransportMode
    origin: str
    destination: str
    departure_time: str
    arrival_time: str
    duration: float  # 小时
    price: float
    distance: float  # 公里
    comfort_score: float  # 舒适度评分 0-10
    reliability_score: float  # 可靠性评分 0-10
    transfer_time: float = 0  # 换乘时间（小时）
    transfer_cost: float = 0  # 换乘费用
    details: Dict = None

@dataclass
class Route:
    """完整路线"""
    legs: List[TransportLeg]
    total_time: float
    total_cost: float
    total_distance: float
    transfers: int
    comfort_score: float
    reliability_score: float
    optimization_score: float
    tags: List[str]
    description: str

class CityHub:
    """城市交通枢纽信息"""
    def __init__(self, name: str, iata_code: str = None, 
                 has_airport: bool = False, has_hsr: bool = False,
                 has_train: bool = False, has_bus: bool = False,
                 nearby_cities: List[str] = None):
        self.name = name
        self.iata_code = iata_code
        self.has_airport = has_airport
        self.has_hsr = has_hsr
        self.has_train = has_train
        self.has_bus = has_bus
        self.nearby_cities = nearby_cities or []

class SmartTravelPlanner:
    """智能出行规划器"""
    
    def __init__(self):
        self.city_hubs = self._init_city_hubs()
        self.transport_apis = self._init_transport_apis()
        
    def _init_city_hubs(self) -> Dict[str, CityHub]:
        """初始化城市交通枢纽信息"""
        return {
            # 一线城市
            '北京': CityHub('北京', 'PEK', True, True, True, True, ['天津', '石家庄']),
            '上海': CityHub('上海', 'PVG', True, True, True, True, ['南京', '杭州', '苏州']),
            '广州': CityHub('广州', 'CAN', True, True, True, True, ['深圳', '佛山']),
            '深圳': CityHub('深圳', 'SZX', True, True, True, True, ['广州', '香港']),
            
            # 二线城市
            '大连': CityHub('大连', 'DLC', True, False, True, True, ['沈阳', '青岛', '天津']),
            '合肥': CityHub('合肥', 'HFE', True, True, True, True, ['南京', '上海', '武汉', '杭州']),
            '南京': CityHub('南京', 'NKG', True, True, True, True, ['上海', '杭州', '合肥']),
            '杭州': CityHub('杭州', 'HGH', True, True, True, True, ['上海', '南京', '宁波']),
            '武汉': CityHub('武汉', 'WUH', True, True, True, True, ['长沙', '郑州', '合肥']),
            '成都': CityHub('成都', 'CTU', True, True, True, True, ['重庆', '西安']),
            '重庆': CityHub('重庆', 'CKG', True, True, True, True, ['成都', '贵阳']),
            '西安': CityHub('西安', 'XIY', True, True, True, True, ['成都', '郑州']),
            
            # 三线城市
            '青岛': CityHub('青岛', 'TAO', True, False, True, True, ['大连', '济南']),
            '济南': CityHub('济南', 'TNA', True, True, True, True, ['青岛', '天津']),
            '天津': CityHub('天津', 'TSN', True, True, True, True, ['北京', '大连']),
            '沈阳': CityHub('沈阳', 'SHE', True, True, True, True, ['大连', '长春']),
        }
    
    def _init_transport_apis(self) -> Dict:
        """初始化交通API客户端"""
        try:
            from backend.train_api import TrainJuheClient, FlightJuheClient
            from api_keys_complete import JUHE_TRAIN_APPKEY, JUHE_FLIGHT_APPKEY
            
            return {
                'flight': FlightJuheClient(JUHE_FLIGHT_APPKEY, max_segments=0) if JUHE_FLIGHT_APPKEY else None,
                'train': TrainJuheClient(JUHE_TRAIN_APPKEY) if JUHE_TRAIN_APPKEY else None,
            }
        except Exception as e:
            print(f"API初始化失败: {e}")
            return {'flight': None, 'train': None}
    
    def find_routes(self, origin: str, destination: str, 
                   date: str = None, optimization: OptimizationType = OptimizationType.BALANCED,
                   max_transfers: int = 2, time_window: Tuple[str, str] = None) -> List[Route]:
        """
        智能路径规划主函数
        
        Args:
            origin: 出发地
            destination: 目的地
            date: 出发日期
            optimization: 优化类型
            max_transfers: 最大换乘次数
            time_window: 时间窗口 (earliest, latest)
        """
        if not date:
            date = datetime.now().strftime('%Y-%m-%d')
        
        print(f"🚀 开始智能规划: {origin} → {destination} ({date})")
        
        # 1. 获取直达路线
        direct_routes = self._get_direct_routes(origin, destination, date)
        print(f"📋 找到 {len(direct_routes)} 条直达路线")
        
        # 2. 获取中转路线
        transfer_routes = self._get_transfer_routes(origin, destination, date, max_transfers)
        print(f"🔄 找到 {len(transfer_routes)} 条中转路线")
        
        # 3. 合并所有路线
        all_routes = direct_routes + transfer_routes
        
        # 4. 应用时间窗口过滤
        if time_window:
            all_routes = self._filter_by_time_window(all_routes, time_window)
        
        # 5. 全局优化排序
        optimized_routes = self._optimize_routes(all_routes, optimization)
        
        # 6. 生成智能推荐
        recommended_routes = self._generate_recommendations(optimized_routes)
        
        print(f"✅ 最终推荐 {len(recommended_routes)} 条路线")
        return recommended_routes
    
    def _get_direct_routes(self, origin: str, destination: str, date: str) -> List[Route]:
        """获取直达路线"""
        routes = []
        
        # 获取所有交通选项并转换为路线
        all_legs = self._get_all_transport_options(origin, destination, date)
        
        # 将每个交通段转换为单段路线
        for leg in all_legs:
            route = Route(
                legs=[leg],
                total_time=leg.duration,
                total_cost=leg.price,
                total_distance=leg.distance,
                transfers=0,
                comfort_score=leg.comfort_score,
                reliability_score=leg.reliability_score,
                optimization_score=0,  # 稍后计算
                tags=['直达', leg.mode.value],
                description=f"{leg.mode.value}直达，{leg.duration:.1f}小时，¥{leg.price}"
            )
            routes.append(route)
        
        return routes
    
    def _get_transfer_routes(self, origin: str, destination: str, date: str, max_transfers: int) -> List[Route]:
        """获取中转路线"""
        routes = []
        
        # 获取中转候选城市
        transfer_candidates = self._get_transfer_candidates(origin, destination)
        print(f"🎯 中转候选城市: {transfer_candidates}")
        
        for transfer_city in transfer_candidates:
            # 第一段：出发地到中转城市
            first_legs = self._get_all_transport_options(origin, transfer_city, date)
            
            # 第二段：中转城市到目的地
            second_legs = self._get_all_transport_options(transfer_city, destination, date)
            
            # 组合路线
            for first_leg in first_legs:
                for second_leg in second_legs:
                    route = self._combine_legs([first_leg, second_leg], transfer_city)
                    if route:
                        routes.append(route)
        
        return routes
    
    def _get_transfer_candidates(self, origin: str, destination: str) -> List[str]:
        """获取中转候选城市"""
        candidates = []
        
        # 获取出发地和目的地的交通枢纽信息
        origin_hub = self.city_hubs.get(origin)
        dest_hub = self.city_hubs.get(destination)
        
        if not origin_hub or not dest_hub:
            return candidates
        
        # 策略1: 出发地周边城市
        candidates.extend(origin_hub.nearby_cities[:3])
        
        # 策略2: 目的地周边城市
        candidates.extend(dest_hub.nearby_cities[:3])
        
        # 策略3: 主要交通枢纽
        major_hubs = ['北京', '上海', '广州', '深圳', '南京', '杭州', '武汉', '成都']
        for hub in major_hubs:
            if hub not in [origin, destination] and hub not in candidates:
                candidates.append(hub)
        
        # 去重并限制数量
        return list(set(candidates))[:8]
    
    def _get_all_transport_options(self, origin: str, destination: str, date: str) -> List[TransportLeg]:
        """获取两地间的所有交通选项"""
        legs = []
        
        # 航班选项
        flight_legs = self._get_flight_legs(origin, destination, date)
        legs.extend(flight_legs)
        
        # 高铁选项
        hsr_legs = self._get_train_legs(origin, destination, date, high_speed_only=True)
        legs.extend(hsr_legs)
        
        # 普通火车选项
        train_legs = self._get_train_legs(origin, destination, date, high_speed_only=False)
        legs.extend(train_legs)
        
        return legs
    
    def _get_flight_legs(self, origin: str, destination: str, date: str) -> List[TransportLeg]:
        """获取航班选项"""
        legs = []
        
        flight_client = self.transport_apis.get('flight')
        if not flight_client:
            return legs
        
        try:
            # 获取IATA代码
            origin_iata = self.city_hubs.get(origin, CityHub(origin)).iata_code
            dest_iata = self.city_hubs.get(destination, CityHub(destination)).iata_code
            
            if not origin_iata or not dest_iata:
                return legs
            
            flights = flight_client.query(origin_iata, dest_iata, date)
            
            for flight in flights:
                leg = TransportLeg(
                    mode=TransportMode.FLIGHT,
                    origin=origin,
                    destination=destination,
                    departure_time=flight.get('departure_time', ''),
                    arrival_time=flight.get('arrival_time', ''),
                    duration=self._parse_duration(flight.get('duration', '')),
                    price=flight.get('price', 0),
                    distance=self._estimate_distance(origin, destination),
                    comfort_score=8.5,  # 航班舒适度较高
                    reliability_score=7.0,  # 航班可靠性中等
                    details=flight
                )
                legs.append(leg)
                
        except Exception as e:
            print(f"航班查询失败 {origin}→{destination}: {e}")
        
        return legs
    
    def _get_train_legs(self, origin: str, destination: str, date: str, high_speed_only: bool = False) -> List[TransportLeg]:
        """获取火车选项"""
        legs = []
        
        train_client = self.transport_apis.get('train')
        if not train_client:
            return legs
        
        try:
            trains = train_client.query(origin, destination, date)
            
            for train in trains:
                # 判断是否为高铁
                train_no = train.get('train_number', '')
                is_hsr = train_no.startswith(('G', 'D'))
                
                if high_speed_only and not is_hsr:
                    continue
                
                leg = TransportLeg(
                    mode=TransportMode.HIGH_SPEED_RAIL if is_hsr else TransportMode.TRAIN,
                    origin=origin,
                    destination=destination,
                    departure_time=train.get('departure_time', ''),
                    arrival_time=train.get('arrival_time', ''),
                    duration=self._parse_duration(train.get('duration', '')),
                    price=train.get('price', 0),
                    distance=self._estimate_distance(origin, destination),
                    comfort_score=9.0 if is_hsr else 6.0,
                    reliability_score=9.5 if is_hsr else 8.0,
                    details=train
                )
                legs.append(leg)
                
        except Exception as e:
            print(f"火车查询失败 {origin}→{destination}: {e}")
        
        return legs
    
    def _combine_legs(self, legs: List[TransportLeg], transfer_city: str) -> Optional[Route]:
        """组合多个交通段为完整路线"""
        if len(legs) < 2:
            return None
        
        # 计算换乘时间
        transfer_time = self._calculate_transfer_time(legs[0], legs[1])
        
        # 计算总时间和费用
        total_time = sum(leg.duration for leg in legs) + transfer_time
        total_cost = sum(leg.price for leg in legs)
        total_distance = sum(leg.distance for leg in legs)
        
        # 计算舒适度和可靠性
        comfort_score = sum(leg.comfort_score for leg in legs) / len(legs)
        reliability_score = min(leg.reliability_score for leg in legs)  # 取最低值
        
        # 生成标签和描述
        tags = self._generate_route_tags(legs, transfer_city)
        description = self._generate_route_description(legs, transfer_city)
        
        return Route(
            legs=legs,
            total_time=total_time,
            total_cost=total_cost,
            total_distance=total_distance,
            transfers=len(legs) - 1,
            comfort_score=comfort_score,
            reliability_score=reliability_score,
            optimization_score=0,  # 稍后计算
            tags=tags,
            description=description
        )
    
    def _optimize_routes(self, routes: List[Route], optimization: OptimizationType) -> List[Route]:
        """全局优化路线排序"""
        for route in routes:
            route.optimization_score = self._calculate_optimization_score(route, optimization)
        
        # 按优化分数排序
        return sorted(routes, key=lambda r: r.optimization_score, reverse=True)
    
    def _calculate_optimization_score(self, route: Route, optimization: OptimizationType) -> float:
        """计算路线优化分数"""
        if optimization == OptimizationType.TIME:
            # 时间最短：分数与时间成反比
            return 100 / (1 + route.total_time)
        elif optimization == OptimizationType.COST:
            # 费用最低：分数与费用成反比
            return 100 / (1 + route.total_cost / 100)
        elif optimization == OptimizationType.COMFORT:
            # 舒适度最高：直接使用舒适度分数
            return route.comfort_score * 10
        else:  # BALANCED
            # 平衡优化：综合考虑时间、费用、舒适度
            time_score = 100 / (1 + route.total_time)
            cost_score = 100 / (1 + route.total_cost / 100)
            comfort_score = route.comfort_score * 10
            reliability_score = route.reliability_score * 10
            
            return (time_score * 0.3 + cost_score * 0.3 + 
                   comfort_score * 0.2 + reliability_score * 0.2)
    
    def _generate_recommendations(self, routes: List[Route]) -> List[Route]:
        """生成智能推荐"""
        if not routes:
            return routes
        
        # 为路线添加推荐标签
        for i, route in enumerate(routes):
            if i == 0:
                route.tags.append('系统推荐')
            elif route.total_cost < 300:
                route.tags.append('价格优惠')
            elif route.total_time < 4:
                route.tags.append('时间最短')
            elif route.transfers == 0:
                route.tags.append('直达便捷')
        
        return routes
    
    # 辅助方法
    def _parse_duration(self, duration_str: str) -> float:
        """解析时长字符串为小时数"""
        try:
            if '小时' in duration_str and '分' in duration_str:
                parts = duration_str.split('小时')
                hours = float(parts[0])
                minutes_part = parts[1].split('分')[0]
                minutes = float(minutes_part) if minutes_part else 0
                return hours + minutes / 60
            elif ':' in duration_str:
                h, m = duration_str.split(':')[:2]
                return int(h) + int(m) / 60
            else:
                return float(duration_str) if duration_str else 0
        except:
            return 0
    
    def _estimate_distance(self, origin: str, destination: str) -> float:
        """估算两地距离（公里）"""
        # 简化的距离估算，实际应该使用地理坐标计算
        distances = {
            ('大连', '合肥'): 1200,
            ('大连', '北京'): 800,
            ('大连', '上海'): 1000,
            ('北京', '上海'): 1200,
            ('北京', '广州'): 2000,
            ('上海', '广州'): 1200,
        }
        return distances.get((origin, destination), 500)
    
    def _calculate_transfer_time(self, leg1: TransportLeg, leg2: TransportLeg) -> float:
        """计算换乘时间"""
        # 根据交通方式计算换乘时间
        if leg1.mode == TransportMode.FLIGHT and leg2.mode == TransportMode.FLIGHT:
            return 2.0  # 航班换乘需要2小时
        elif leg1.mode == TransportMode.HIGH_SPEED_RAIL and leg2.mode == TransportMode.HIGH_SPEED_RAIL:
            return 0.5  # 高铁换乘需要30分钟
        else:
            return 1.0  # 其他情况1小时
    
    def _generate_route_tags(self, legs: List[TransportLeg], transfer_city: str) -> List[str]:
        """生成路线标签"""
        tags = []
        
        if len(legs) == 1:
            tags.append('直达')
        else:
            tags.append(f'经{transfer_city}中转')
        
        modes = [leg.mode.value for leg in legs]
        if 'flight' in modes:
            tags.append('飞机')
        if 'high_speed_rail' in modes:
            tags.append('高铁')
        if 'train' in modes:
            tags.append('火车')
        
        return tags
    
    def _generate_route_description(self, legs: List[TransportLeg], transfer_city: str) -> str:
        """生成路线描述"""
        if len(legs) == 1:
            leg = legs[0]
            return f"{leg.mode.value}直达，{leg.duration:.1f}小时，¥{leg.price}"
        else:
            total_time = sum(leg.duration for leg in legs)
            total_cost = sum(leg.price for leg in legs)
            return f"经{transfer_city}中转，总时长{total_time:.1f}小时，总费用¥{total_cost}"
    
    def _filter_by_time_window(self, routes: List[Route], time_window: Tuple[str, str]) -> List[Route]:
        """按时间窗口过滤路线"""
        earliest, latest = time_window
        filtered = []
        
        for route in routes:
            if route.legs:
                first_leg = route.legs[0]
                dep_time = first_leg.departure_time
                
                # 简单的时间比较（实际应该更精确）
                if earliest <= dep_time <= latest:
                    filtered.append(route)
        
        return filtered

# 使用示例
if __name__ == "__main__":
    planner = SmartTravelPlanner()
    
    # 测试智能规划
    routes = planner.find_routes(
        origin="大连",
        destination="合肥", 
        date="2025-09-17",
        optimization=OptimizationType.BALANCED,
        max_transfers=2
    )
    
    print(f"\n🎯 智能规划结果:")
    for i, route in enumerate(routes[:5]):
        print(f"\n方案 {i+1}: {route.description}")
        print(f"  总时间: {route.total_time:.1f}小时")
        print(f"  总费用: ¥{route.total_cost}")
        print(f"  换乘次数: {route.transfers}")
        print(f"  标签: {', '.join(route.tags)}")
        print(f"  优化分数: {route.optimization_score:.2f}")